package com.zijidelu.luframework.infrastructure.persistence.repository.core.domain;

import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.domain.exception.RepositoryException;
import com.zijidelu.luframework.domain.model.aggregate.AggregateRoot;
import com.zijidelu.luframework.domain.model.aggregate.AggregateRootFactory;
import com.zijidelu.luframework.domain.model.entity.Entity;
import com.zijidelu.luframework.domain.model.entity.EntityRelation;
import com.zijidelu.luframework.domain.repository.AggregateRepository;
import com.zijidelu.luframework.infrastructure.converter.AggregateRootConverter;
import com.zijidelu.luframework.infrastructure.factory.AggregateVault;
import com.zijidelu.luframework.infrastructure.factory.ConverterVault;
import com.zijidelu.luframework.infrastructure.factory.DataVault;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.base.AbstractRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.DataRepository;
import com.zijidelu.luframework.utils.lang.reflect.generic.GenericResolveUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 基础聚合根仓库实现类。
 * <p>
 * 该类提供了聚合根持久化的核心实现，通过抽象化执行计划，实现了 {@code save} 和 {@code saveAll} 方法的高度复用，
 * 并严格遵循“创建 -> 更新 -> 删除”的CRUD操作顺序，以确保数据一致性和操作逻辑的严谨性。
 *
 * @author ZIJIDELU
 * @datetime 2025/11/13 00:01
 */
@Slf4j
public abstract class AbstractAggregateRepository<
        P extends PO,
        D extends DataModel,
        E extends Entity<D>,
        A extends AggregateRoot<D, E>
        > extends AbstractRepository<P, D> implements AggregateRepository<D, E, A> {

    private final Class<A> aggregateRootClass = initializeAggregateRootClass();
    private final Class<E> rootEntityClass = initializeEntityClass();
    private final Class<D> rootDataModelClass = initializeDataModelClass();
    @Setter(onMethod_ = {@Autowired})
    private AggregateRootConverter<P, D, E, A> aggregateConverter;
    @Setter(onMethod_ = {@Autowired})
    private DataVault dataVault;
    @Setter(onMethod_ = {@Autowired})
    private AggregateVault aggregateVault;
    @Setter(onMethod_ = {@Autowired})
    private ConverterVault converterVault;
    @Setter(onMethod_ = {@Autowired})
    private ObjectProvider<DataRepository<P, D>> dataRepositoryProvider;
    private DataRepository<P, D> dataRepository;

    public DataRepository<P, D> getDataRepository() {
        if (dataRepository == null) {
            dataRepository = dataRepositoryProvider.stream().findFirst().orElseThrow();
        }
        return dataRepository;
    }

    /**
     * 初始化数据模型类。
     * <p>
     * 该方法通过解析当前类的泛型参数，获取数据模型的实际类型。
     *
     * @return 数据模型类
     */
    @SuppressWarnings("unchecked")
    private Class<D> initializeDataModelClass() {
        try {
            List<Type> generics = GenericResolveUtil.resolveGenericsWithCache(getClass(), AbstractAggregateRepository.class);
            if (generics.size() > 1) {
                return (Class<D>) GenericResolveUtil.getRawType(generics.get(1));
            }
            throw new IllegalStateException("无法解析数据模型类型，泛型参数不足");
        } catch (Exception e) {
            log.error("解析数据模型类型失败", e);
            throw new IllegalStateException("无法解析数据模型类型", e);
        }
    }

    /**
     * 初始化实体类。
     * <p>
     * 该方法通过解析当前类的泛型参数，获取实体的实际类型。
     *
     * @return 实体类
     */
    @SuppressWarnings("unchecked")
    private Class<E> initializeEntityClass() {
        try {
            List<Type> generics = GenericResolveUtil.resolveGenericsWithCache(getClass(), AbstractAggregateRepository.class);
            if (generics.size() > 2) {
                return (Class<E>) GenericResolveUtil.getRawType(generics.get(2));
            }
            throw new IllegalStateException("无法解析实体类型，泛型参数不足");
        } catch (Exception e) {
            log.error("解析实体类型失败", e);
            throw new IllegalStateException("无法解析实体类型", e);
        }
    }

    /**
     * 初始化聚合根类。
     * <p>
     * 该方法通过解析当前类的泛型参数，获取聚合根的实际类型。
     *
     * @return 聚合根类
     */
    @SuppressWarnings("unchecked")
    private Class<A> initializeAggregateRootClass() {
        try {
            List<Type> generics = GenericResolveUtil.resolveGenericsWithCache(getClass(), AbstractAggregateRepository.class);
            if (generics.size() > 3) {
                return (Class<A>) GenericResolveUtil.getRawType(generics.get(3));
            }
            throw new IllegalStateException("无法解析聚合根类型，泛型参数不足");
        } catch (Exception e) {
            log.error("解析聚合根类型失败", e);
            throw new IllegalStateException("无法解析聚合根类型", e);
        }
    }

    /**
     * 查找根实体。
     * <p>
     * 该方法根据实体ID查询数据模型，将其转换为实体对象。
     *
     * @param rootEntityId 实体ID
     * @return 根实体对象的 Optional 包装
     */
    protected Optional<E> findRootEntity(Serializable rootEntityId) {
        if (rootEntityId == null) {
            return Optional.empty();
        }

        final D data = getDataRepository().findById(rootEntityId);
        return Optional.ofNullable(aggregateConverter.dataToEntity(data));
    }

    @Override
    public void load(A aggregateRoot) {
        Objects.requireNonNull(aggregateRoot, "aggregateRoot is null");
        AggregateExecutionPlan.of(Collections.singleton(aggregateRoot), rootDataModelClass).executeLoad(dataVault, converterVault);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void persist(A aggregateRoot) {
        Objects.requireNonNull(aggregateRoot, "aggregateRoot is null");
        AggregateExecutionPlan.of(Collections.singletonList(aggregateRoot), rootDataModelClass).executePersist(dataVault);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void persistBatch(Collection<A> aggregateRoots) {
        Objects.requireNonNull(aggregateRoots, "aggregateRoots is null");
        AggregateExecutionPlan.of(aggregateRoots, rootDataModelClass).executePersist(dataVault);
    }

    @Override
    public Optional<A> findById(Serializable rootEntityId) {
        final E rootEntity = findRootEntity(rootEntityId).orElseThrow(() -> new RepositoryException("Root entity not found"));
        final A a = AggregateRootFactory.from(aggregateRootClass, rootEntity);
        return Optional.of(a);
    }

    @Override
    public List<A> findBatchById(Collection<Serializable> idColl) {
        if (CollectionUtils.isEmpty(idColl)) {
            return Collections.emptyList();
        }

        final List<D> dataList = getDataRepository().findBatchById(idColl);
        if (CollectionUtils.isEmpty(dataList)) {
            return Collections.emptyList();
        }

        final List<A> aList = new ArrayList<>(dataList.size());
        for (D d : dataList) {
            final E e = aggregateConverter.dataToEntity(d);
            final A a = AggregateRootFactory.from(aggregateRootClass, e);
            aList.add(a);
        }

        return aList;
    }

    @Override
    public boolean existsById(Serializable id) {
        return getDataRepository().existById(id);
    }

    @Override
    public void deleteById(Serializable id) {
        getDataRepository().deleteById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cascadeDeleteById(Serializable id) {
        // 获取所有子实体类型
        final Set<EntityRelation> entityRelations = aggregateVault.getEntityRelationSet(rootEntityClass);
        for (EntityRelation entityRelation : entityRelations) {
            // 获取子实体数据仓库
            final DataRepository<PO, DataModel> childrenDataRepository = dataVault.getDataRepositoryFor(entityRelation.childType());
            // 删除子实体数据
            childrenDataRepository.delete(wrapper -> wrapper.eq(entityRelation.childForeignKey(), id));
        }
        // 删除父实体数据
        getDataRepository().deleteById(id);
    }

    @Override
    public void deleteBatchById(Collection<Serializable> idColl) {
        getDataRepository().deleteBatchById(idColl);
    }

}